package posts

import (
	"context"
	"fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/resultx"
	"mall/common/utils/pointy"
	"mall/service/forum/model"
	"mall/service/forum/rpc/internal/svc"
	"mall/service/forum/rpc/types/forum"

	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type GetPostsListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewGetPostsListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPostsListLogic {
	return &GetPostsListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

// ##25.04.01## 历史遗留文件，暂不处理
func (l *GetPostsListLogic) GetPostsList(in *forum.PostsListReq) (*forum.PostsListResp, error) {
	if in.Filter == nil || len(*in.Filter) == 0 {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	preloadMap, eagerLoadMap := modelx.ParsePreloadAndEagerLoad(in.Preload, in.EagerLoad)
	logrus.Info(fmt.Sprintf("GetPostsList preloadMap: %+v", preloadMap))

	logrus.Info(fmt.Sprintf("GetPostsList eagerLoadMap: %+v", eagerLoadMap))

	forumPostEntityName := model.RpcEntityNames.ForumPost
	if _, ok := model.RpcEntityPreloadMap[forumPostEntityName]; !ok {
		return &forum.PostsListResp{}, nil
	}

	forumPostRepositoryName := model.RepositoryNames.ForumPost
	columnMap, ok := model.RepositoryPreloadMap[forumPostRepositoryName]
	if !ok {
		return &forum.PostsListResp{}, nil
	}

	var selectCols []string
	if preloadFields, ok := preloadMap[forumPostEntityName]; ok {
		selectCols = modelx.ParseSelectColumns(preloadFields, columnMap)
	}

	filterMap := modelx.ParseFilter(in.Filter, columnMap)
	logrus.Info(fmt.Sprintf("GetPostsList filterMap: %+v", filterMap))
	if filterMap == nil {
		return nil, resultx.StatusError(resultx.REUQEST_PARAM_ERROR, "")
	}

	orderBy := modelx.ParseSorter(in.Sorter, columnMap)
	logrus.Info(fmt.Sprintf("GetPostsList orderBy: %s", orderBy))
	if len(orderBy) == 0 {
		orderBy = model.ForumPostColumns.PostModifiedDate + " DESC"
	}

	res, count, err := l.svcCtx.Post.GetList(l.ctx, model.M{
		"offset": in.Offset,
		"limit":  in.Limit,
		// "search":  in.Search,
		"orderBy": orderBy,
		"select":  strings.Join(selectCols, ","),
	}, 2, filterMap)
	if err != nil {
		return nil, err
	}

	hasNextPage, hasPreviousPage := modelx.ParseCount(count)
	resp := &forum.PostsListResp{
		HasNextPage:     &hasNextPage,
		HasPreviousPage: &hasPreviousPage,
	}

	if len(res) > 0 {
		var ids []any
		for _, v := range res {
			ids = append(ids, v.PostID)
		}

		subEntitySettingMap := make(map[string]map[string]*model.ColumnSetting)
		if eagerLoadEntities, ok := eagerLoadMap[forumPostEntityName]; ok {
			for _, entity := range eagerLoadEntities {
				if entitySettingMap, ok := model.RpcEntityPreloadMap[entity]; ok {
					subEntitySettingMap[entity] = entitySettingMap
				}
			}
		}

		idMediaMap := make(map[uint64][]*forum.MediaInfo)
		forumMediaEntityName := model.RpcEntityNames.ForumMedia
		forumMediaRepositoryName := model.RepositoryNames.ForumMedia
		//WithMedia > 0 查询media
		if in.WithMedia != nil && *in.WithMedia > 0 {
			subPreloadFields, hasSubPreloadFields := preloadMap[forumMediaEntityName]
			subColumnMap, hasSubColumnMap := model.RepositoryPreloadMap[forumMediaRepositoryName]
			if hasSubPreloadFields && hasSubColumnMap {
				subSelectCols := modelx.ParseSelectColumns(subPreloadFields, subColumnMap)

				mediaFilterMap := make(map[string]map[string][]any)
				mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectID] = map[string][]any{
					"in": ids,
				}
				mediaFilterMap[model.ForumAttachmentRelationshipColumns.ObjectType] = map[string][]any{
					"equalTo": {globalkey.AttachmentLogTypeForumPost},
				}
				pageSize := uint64(len(ids) * 3)
				if strings.Contains(","+strings.Join(subSelectCols, ",")+",", ","+model.ForumAttachmentRelationshipColumns.AttachmentOrder+",") {
					pageSize = 0
				}
				subSelectCols = append(subSelectCols, model.ForumAttachmentRelationshipColumns.ObjectID)
				var orderBy = model.ForumAttachmentRelationshipColumns.AttachmentOrder
				mediaList, _, err := l.svcCtx.Post.GetMedia(l.ctx, model.M{
					"orderBy":  orderBy,
					"pageSize": pageSize,
					"select":   strings.Join(subSelectCols, ","),
				}, -1, mediaFilterMap)
				if err != nil {
					return nil, err
				}

				if len(mediaList) > 0 {
					for _, v := range mediaList {
						idMediaMap[v.ObjectID] = append(idMediaMap[v.ObjectID], &forum.MediaInfo{
							Uid:       &v.AttachmentRelationshipID,
							Id:        pointy.GetPointer(strconv.FormatUint(v.AttachmentID, 10)),
							Uri:       &v.AttachmentSource,
							Url:       &v.AttachmentImageURL,
							Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
							Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
							AltText:   &v.AttachmentImageAlt,
							MetaData:  &v.AttachmentImageMeta,
						})
					}
				}
			}
		}
		idMetaMap := make(map[uint64][]*forum.MetaInfo)
		forumPostMetaEntityName := model.RpcEntityNames.ForumPostMeta
		if in.WithMeta != nil && *in.WithMeta > 0 {
			if subPreloadFields, ok := preloadMap[forumPostMetaEntityName]; ok {
				var metaKeys []any
				for _, field := range subPreloadFields {
					metaKeys = append(metaKeys, field)
				}
				if len(metaKeys) > 0 {
					metaFilterMap := make(map[string]map[string][]any)
					metaFilterMap[model.ForumPostMetumColumns.PostID] = map[string][]any{
						"in": ids,
					}
					metaFilterMap[model.ForumPostMetumColumns.MetaKey] = map[string][]any{
						"in": metaKeys,
					}
					metaList, _, err := l.svcCtx.Post.GetMeta(l.ctx, model.M{}, -1, metaFilterMap)
					if err != nil && err != model.ErrNotFound {
						return nil, err
					}

					if len(metaList) > 0 {
						for _, v := range metaList {
							idMetaMap[v.PostID] = append(idMetaMap[v.PostID], &forum.MetaInfo{
								Id:    &v.MetaID,
								Key:   &v.MetaKey,
								Value: &v.MetaValue.String,
							})
						}
					}
				}
			}
		}

		for _, v := range res {
			var media []*forum.MediaInfo
			if ms, ok := idMediaMap[v.PostID]; ok {
				media = ms[:]
			}
			var meta []*forum.MetaInfo
			if ms, ok := idMetaMap[v.PostID]; ok {
				meta = ms[:]
			}
			resp.List = append(resp.List, &forum.PostsInfo{
				Id:             &v.PostID,
				ForumId:        &v.ForumID,
				TopicId:        &v.TopicID,
				ParentId:       &v.ParentID,
				AuthorId:       &v.PostAuthorID,
				AuthorNickname: &v.PostAuthorNickname,
				AuthorAvatar:   &v.PostAuthorAvatar,
				AuthorIP:       &v.PostAuthorIP,
				AuthorRankId:   pointy.GetPointer(uint32(v.PostAuthorRankID)),
				AuthorRoleId:   pointy.GetPointer(uint32(v.PostAuthorRoleID)),
				PostTitle:      &v.PostTitle,
				PostContent:    &v.PostContent,
				PhotoCount:     pointy.GetPointer(uint32(v.PhotoCount)),
				Status:         pointy.GetPointer(uint32(v.PostStatus)),
				CommentStatus:  pointy.GetPointer(uint32(v.CommentStatus)),
				Meta:           meta,
				Media:          media,
				CreatedAt:      pointy.GetPointer(modelx.FormatTime(v.PostDate, "")),
				UpdatedAt:      pointy.GetPointer(modelx.FormatTime(v.PostModifiedDate, "")),
				DeletedAt:      pointy.GetPointer(modelx.FormatNullDotTime(v.DeletedAt, "")),
			})
		}
	}
	resp.Total = uint64(len(resp.List))

	return resp, nil
}
